package chloroform.router

import scaladuct._
import java.lang.reflect.Type
import lists.scala.{ListForProperty, ListsManager}
import chloroform.{TypedProjectEntry, ConfigPageRegister, Project}
import util.GenericAnalysisUtils

/**
 * Created by IntelliJ IDEA.
 * User: zslajchrt
 * Date: 11.4.11
 * Time: 11:38
 */
@SerialVersionUID(1L)
class Router extends ConfigPage[Any] {
  def id = classOf[Router].getName

  type Cookie = RouterContext

  val getCookie = new RouterContext

  def consume(context: Cookie): ConfigResult[Any] = {
    NextPage(new RouterInContext(context))
  }
}

@SerialVersionUID(1L)
class RouterInContext(context: RouterContext) extends ConfigPage[Any] with ListsManager {
  def id = classOf[RouterInContext].getName

  type Cookie = RouterConfig

  val getCookie = new RouterConfig

  def consume(config: Cookie): ConfigResult[Any] = {
    NextPage(new PathSelector(context, config))
  }

  def scalaListForProperty(property: Property[AnyRef]): Option[ListForProperty[AnyRef]] = {
    if (property.name == "pages") {
      val entryList = context.project.getEntryNames
      Some(new ListForProperty[AnyRef](property, entryList, false, true))
    } else None
  }

}

@SerialVersionUID(1L)
class PathSelector(context: RouterContext, routerConfig: RouterConfig) extends ConfigPage[Any]
with scaladuct.lists.ListsManager with HasProductType {

  def id = classOf[RouterInContext].getName

  type Cookie = PathSelectorConfig

  def getCookie() = new PathSelectorConfig

  def consume(selection: Cookie): ConfigResult[Any] = {
    val selPageName = selection.selectedPage
    val projectEntry = context.project.getEntry(selPageName).asInstanceOf[TypedProjectEntry]
    val selPage: ConfigPage[Any] = context.register.getConfigPage(selPageName)
    NextPage(new SelectedPath(selPage, projectEntry.getEntryType))
  }


  def listForProperty(property: Property[AnyRef]): Option[scaladuct.lists.ListForProperty[AnyRef]] = {
    if (property.name == "selectedPage") {
      Some(new scaladuct.lists.ListForProperty[AnyRef](property, routerConfig.pages.asInstanceOf[java.util.List[AnyRef]],
        false, false))
    } else None
  }

  /**
   * Computes the nearest common type ancestor for all selectable pages.
   */
  def getProductType() = {
    val iter = routerConfig.pages.iterator
    var entryTypes: List[Type] = Nil
    while (iter.hasNext) {
      val entryName: String = iter.next
      val entry = context.project.getEntry(entryName).asInstanceOf[TypedProjectEntry]
      entryTypes ::= entry.getEntryType
    }
    val commonType = GenericAnalysisUtils.getCommonType(entryTypes.toArray)
    commonType
  }
}

@SerialVersionUID(1L)
class SelectedPath(selectedPage: ConfigPage[Any], productType: Type) extends ConfigPageDecorator[Any](selectedPage)
with HasProductType {
  def getProductType() = productType
}

@serializable
@SerialVersionUID(1L)
class RouterContext {
  @Ref(name = "?")
  var project: Project = null
  @Ref(name = "?")
  var register: ConfigPageRegister = null
}

@serializable
@SerialVersionUID(1L)
class RouterConfig {
  var pages: java.util.List[String] = null
}

@serializable
@SerialVersionUID(1L)
class PathSelectorConfig {
  var selectedPage: String = null
}


